package com.wh.minio.container.controller;

import com.google.gson.Gson;
import com.wh.minio.container.common.MinioClientUtils;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by dingYi on 2018/7/3.
 */
@Controller
@RequestMapping("/file")
public class FileUploadController {
    /**
     * 直接接收前端解析好的存储得有zip子文件路径的json，存至map中
     * @param jsonMap 前端传输过来的zip解析信息
     * @return map 后端根据zip解析信息存储的map对象
     */
    @RequestMapping(value = "/mapResolve", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, String> mapResolve(@RequestParam(value = "jsonMap", required = false)String jsonMap){
        return transferToMap(jsonMap);
    }

    /**
     * 前端选择ZIP上传至服务器后解析出ZIP的文件，返回存储得有对应信息的JSON
     * @param file
     * @param jsonMap
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/resolve", method = RequestMethod.POST)
    @ResponseBody
    public String fileResolve(
            @RequestParam(value = "file", required = false)MultipartFile file,
            @RequestParam(value = "jsonMap", required = false)String jsonMap,
            HttpServletRequest request) throws Exception {
        //创建返回的resultMap，返回前做json化处理
        Map<String, String> resultMap = new HashMap<>();
        if (file == null || file.isEmpty() || file.getBytes().length <= 0){
            resultMap.put("result","fail");
            resultMap.put("message", "please upload a non-empty file");
            return new JSONObject(resultMap).toString();
        }
        //设置暂存路径
        String realPath = request.getSession().getServletContext().getRealPath("/");
        String uploadPath = realPath + "upload/";
        //获取zip名称
        String fileOriginalFileName = file.getOriginalFilename();
        String fileType = fileOriginalFileName.substring(fileOriginalFileName.lastIndexOf(".")).toLowerCase();
        if (fileType.equals(".zip")) {
            //对接受到前端上传过来的file做一次暂存，然后解析，之后再删除暂存的file文件
            File pushFile = new File(uploadPath  + "/" + fileOriginalFileName);
            File descFile = new File(uploadPath);
            if (!descFile.exists()) {
                descFile.mkdirs();
            }
            //将传输过来的MultipartFile存至本地
            file.transferTo(pushFile);
            //根据本地存储下来的file创建zipFile
            ZipFile zipFile = new ZipFile(pushFile);
            //获取bucket名称
            String bucket = fileOriginalFileName.substring(0, fileOriginalFileName.indexOf("."));

            //将解析过的zip信息存储至map，根据map遍历zip文件
            Map<String, String> map = transferToMap(jsonMap);
            try{
                //判断是否存在此bucket，若存在则删除后再创建，不存在则直接创建
                if(!MinioClientUtils.getInstance().isExistbucket(bucket)){
                    MinioClientUtils.getInstance().createBucket(bucket);
                }else{
                    MinioClientUtils.getInstance().removeBucket(bucket);
                    MinioClientUtils.getInstance().createBucket(bucket);
                }
                //循环遍历zip的子文件，做上传操作
                for (String key : map.keySet()) {
                    ZipEntry zipEntry = zipFile.getEntry(map.get(key));
                    if(zipEntry != null){
                        //获取objectName
                        String objectName = zipEntry.getName();
                        //将zip文件的子文件转化为Input流
                        InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry));
                        //将zip文件流上传
                        MinioClientUtils.getInstance().uploadStream(bucket, objectName, inputStream, null);
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                //上传过程失败后将已上传的bucket删除
                try {
                    //上传失败后尝试删除bucket
                    if(!MinioClientUtils.getInstance().isExistbucket(bucket)){
                        MinioClientUtils.getInstance().createBucket(bucket);
                    }
                }catch (Exception e1){
                    e1.printStackTrace();
                }
                resultMap.put("result","fail");
                resultMap.put("message", e.getMessage());
                return new JSONObject(resultMap).toString();
            }finally {
                //关闭zipFile，并删除
                zipFile.close();
                pushFile.delete();
            }
            resultMap.put("result","success");
            resultMap.put("message", "file upload successfully");
            return new JSONObject(resultMap).toString();
        }
        resultMap.put("result","fail");
        resultMap.put("message", "please upload a file of type zip");
        return new JSONObject(resultMap).toString();
    }

    private Map<String, String> transferToMap(String jsonMap) {
        if (jsonMap != null && !jsonMap.equals("")){
            try {
                Gson gson = new Gson();
                Map<String, String> map = new HashMap<>();
                map = gson.fromJson(jsonMap, map.getClass());
                return map;
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }


    public static final InputStream byte2Input(byte[] buf) {
        return new ByteArrayInputStream(buf);
    }

    public static final byte[] input2byte(InputStream inStream)
            throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while ((rc = inStream.read(buff, 0, 100)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] in2b = swapStream.toByteArray();
        return in2b;
    }

}
